package com.lagou.zookeeper.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.util.Objects;
import java.util.Properties;


@Configuration
@MapperScan(basePackages = "com.lagou.zookeeper.mapper")
public class MyBatisConfig {

    private SqlSessionFactory sqlSessionFactory;

    private CuratorFramework client;

    private String nodeName = "/DatabaseConfig";

    public MyBatisConfig() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.builder()
                .connectString("192.168.33.19:2181")
                .sessionTimeoutMs(50000)
                .connectionTimeoutMs(30000)
                .retryPolicy(retryPolicy)
                .namespace("Configuration")
                .build();
        client.start();
    }

    /**
     * 创建数据源
     */
    @Bean
    public DataSource getDataSource() throws Exception {
        Properties databaseConfiguration = getDatabaseConfiguration();
        Properties props = new Properties();
        props.put("driverClassName", databaseConfiguration.getProperty("jdbc.driver"));
        props.put("url", databaseConfiguration.getProperty("jdbc.url"));
        props.put("username", databaseConfiguration.getProperty("jdbc.username"));
        props.put("password", databaseConfiguration.getProperty("jdbc.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //指定数据源(这个必须有，否则报错)
        sqlSessionFactoryBean.setDataSource(dataSource);
        //指定xml文件位置
        sqlSessionFactory = sqlSessionFactoryBean.getObject();
        addDataBaseConfigurationListener();
        return sqlSessionFactory;
    }

    public Properties getDatabaseConfiguration() {
        Properties properties = null;
        try {
            byte[] bytes = client.getData().forPath(nodeName);
            properties = new Properties();
            properties.load(new ByteArrayInputStream(bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (properties == null) {
            throw new RuntimeException("数据库配置不存在");
        }

        return properties;
    }

    /**
     * 数据库配置信息修改监听器
     */
    private void addDataBaseConfigurationListener() {
        NodeCache nodeCache = new NodeCache(client, nodeName, false);
        try {
            nodeCache.getListenable().addListener(new NodeCacheListener() {
                @Override
                public void nodeChanged() throws Exception {
                    updateDatabaseConfiguration(nodeCache);
                }
            });
            nodeCache.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 更新数据库配置信息
     *
     * @param nodeCache
     */
    private void updateDatabaseConfiguration(NodeCache nodeCache) {
        Properties databaseConfiguration = new Properties();
        try {
            databaseConfiguration.load(new ByteArrayInputStream(nodeCache.getCurrentData().getData()));
            if (!Objects.isNull(sqlSessionFactory)) {
                DruidDataSource druidDataSource = (DruidDataSource) sqlSessionFactory.getConfiguration().getEnvironment().getDataSource();
                druidDataSource.close();
                druidDataSource.restart();
                druidDataSource.setUrl(databaseConfiguration.getProperty("jdbc.url"));
                druidDataSource.setUsername(databaseConfiguration.getProperty("jdbc.username"));
                druidDataSource.setPassword(databaseConfiguration.getProperty("jdbc.password"));
                druidDataSource.setDriverClassName(databaseConfiguration.getProperty("jdbc.driver"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
